local cjson = require("cjson")

local ngx_req = ngx.req
local ngx_log = ngx.log
local ngx_print = ngx.print
local ngx_exit = ngx.exit

local updateurl = "https://api.weixin.qq.com/cgi-bin/token"
local ticketurl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket"

local updateTime = wechat_config.accessTokenUpdateTime or 6000

local function _verify_request_params(params)
  if params.method ~= "GET" then
    return nil, "register not support " .. params.method .. " method"
  end
  if not params.key then
    return nil, "missing key"
  end
  if not params.app_id then
    return nil, "missing app_id"
  end
  if not params.app_secret then
    return nil, "missing app_secret"
  end
  return true
end

local args = ngx_req.get_uri_args()

local params = {
  method = ngx_req.get_method(),
  key = args.key,
  app_id = args.appid,
  app_secret = args.secret,
}

local ok, err = _verify_request_params(params)

if not ok then
  ngx_log(ngx.ERR, "failed to verify server: ", err)
  ngx_print(cjson.encode({ errmsg = "failed to verify request: " .. err }))
  return ngx_exit(ngx.HTTP_OK)
end

ngx.header["Content-Type"] = "application/json;charset=UTF-8"

if not ok then
  ngx_print(cjson.encode({ errmsg = "failed to verify register : " .. err }))
  return ngx_exit(ngx.HTTP_OK)
end

local red = require("resty.wechat.utils.redis"):connect(wechat_config.redis).redis

local app_key = params.key
local key_exist = red:sismember("app_set", app_key)

if key_exist and key_exist == 1 then
  ngx_print(cjson.encode({ errmsg = "app_key:[" .. app_key .. "] has registed!" }))
  return ngx_exit(ngx.HTTP_OK)
end

local accessTokenKey = "access_token:" .. app_key
local jsapiTicketKey = "ticket:" .. app_key

local updateparam = {
  method = "GET",
  query = {
    grant_type = "client_credential",
    appid = params.app_id,
    secret = params.app_secret,
  },
  ssl_verify = false,
  headers = { ["Content-Type"] = "application/x-www-form-urlencoded" },
}

local res, err = require("resty.wechat.utils.http").new():request_uri(updateurl, updateparam)

if not res or err or tostring(res.status) ~= "200" then
  ngx_print(cjson.encode({ errmsg = "failed to update access token: " .. err or tostring(res.status) }))
  return ngx_exit(ngx.HTTP_OK)
end
local resbody = cjson.decode(res.body)
if not resbody.access_token then
  ngx_print(cjson.encode({ errmsg = "failed to update access token, body : " .. res.body }))
  return ngx_exit(ngx.HTTP_OK)
end

local ok, err = red:setex(accessTokenKey, updateTime - 1, resbody.access_token)
if not ok then
  ngx_print(cjson.encode({ errmsg = "failed to set access token: " .. err }))
  return ngx_exit(ngx.HTTP_OK)
end

ngx_log(ngx.NOTICE, "succeed to set access token: ", res.body)

-- refresh jsapi_ticket after refresh access_token

local ticketparam = {
  method = "GET",
  query = {
    type = "jsapi",
  },
  ssl_verify = false,
  headers = { ["Content-Type"] = "application/x-www-form-urlencoded" },
}

ticketparam.query.access_token = resbody.access_token

local res, err = require("resty.wechat.utils.http").new():request_uri(ticketurl, ticketparam)

ticketparam.query.access_token = nil

if not res or err or tostring(res.status) ~= "200" then
  ngx_print(cjson.encode({ errmsg = "failed to update jsapi ticket: " .. err or tostring(res.status) }))
  return ngx_exit(ngx.HTTP_OK)
end

local resbody = cjson.decode(res.body)
if not resbody.ticket then
  ngx_print(cjson.encode({ errmsg = "failed to update jsapi ticket: " .. res.body }))
  return ngx_exit(ngx.HTTP_OK)
end

local ok, err = red:setex(jsapiTicketKey, updateTime - 1, resbody.ticket)
if not ok then
  ngx_print(cjson.encode({ errmsg = "failed to set jsapi ticket: " .. err }))
  return ngx_exit(ngx.HTTP_OK)
end

ngx_log(ngx.NOTICE, "succeed to set jsapi ticket: ", res.body)

red:sadd("app_set", app_key)
red:hset("app_data:" .. app_key, "app_id", params.app_id)
red:hset("app_data:" .. app_key, "app_secret", params.app_secret)

ngx_print(cjson.encode({ errmsg = "sucess" }))
return ngx_exit(ngx.HTTP_OK)
